package com.wangzhen.codebase.transfermoney.lock0;

public class NotSafeAccount {

    private Integer balance;

    public NotSafeAccount(Integer balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account{" +
                "balance=" + balance +
                '}';
    }

    // 1、首先sourceAccount是必须加访问控制的，例如：A这个账户同时向B、C两个账户转账100块，A账户余额100元，
    // 如果不加访问控制的话,线程1和线程2同时执行，那就会出现自己剩余了100块，
    // 但是向BC两个账户却都转账了100元,然后账户A出现负金额的情况
    // 2、target账户也是需要加锁的，原因如下：在线程1中对target的账户余额进行增加，但是在线程2中对target
//    账户余额可能已经修改过了，此时如果线程1拿着之前target的账户余额进行计算，那么就会出现错误；

    public void transfer(NotSafeAccount target, Integer account) {
        if (this.balance.intValue() >= account.intValue()) {
            this.balance -= account;
            target.balance += account;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        // 这个演示的是source这个账户，在没有加访问控制的情况下，同时向target1/2/3这三个账户转账
        // 果然不出意外的发生了source账户金额为负的情况
       /* Account source = new Account(100);
        Account target1 = new Account(0);
        Account target2 = new Account(0);
        Account target3 = new Account(0);

        Thread t1 = new Thread(()-> {source.transfer(target1, 100);});
        Thread t2 = new Thread(()-> {source.transfer(target2, 100);});
        Thread t3 = new Thread(()-> {source.transfer(target3, 100);});
        t1.start();t2.start();t3.start();

        t1.join();t2.join();t3.join();

        System.out.println(source);
        System.out.println(target1);
        System.out.println(target2);
        System.out.println(target3);*/

        // 演示的效果在于：如果不给target账户加锁，那么线程1忘target账户加100，线程2忘target账户减100，
        // 最终正常的结果应该是target=100，但是多次运行之后，会发现target1账户的金额会出现等于200的情况
        NotSafeAccount source1 = new NotSafeAccount(100);
        NotSafeAccount target1 = new NotSafeAccount(100);
        NotSafeAccount target2 = new NotSafeAccount(100);

        Thread t1 = new Thread(()-> {source1.transfer(target1, 100);});
        Thread t2 = new Thread(()-> {target1.transfer(target2, 100);});
        t2.start();t1.start();

        t1.join();t2.join();

        System.out.println(source1);
        System.out.println(target1);
        System.out.println(target2);
    }
}
